﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;


namespace my_rs232
{
    public partial class Form1 : Form

    {
        //串口配置
        public string[] System_set= new string[10];
        //串口序列
        public string[] Rs232_str= new string[100];
        //按钮提示信息
        public string[] tooltip_str= new string[100];
        //串号是否生效
        //public bool [] visible_str = new bool [100];
        public string inifilename;
        public int but_con;
        public bool OnWatch = false;
        string[] myarges;
 

        

        public enum LogMsgType { Incoming, Outgoing, Normal, Warning, Error };
        

        public Form1(string[] arges)
        {
            //inifilename = "232.ini";
            inifilename = ".//232.ini";
            but_con = 0;
            myarges = arges;
            InitializeComponent();


        }

        private void Form1_Load(object sender, EventArgs e)
        {

            RS232_reset();
            if (myarges.Length != 0)
            {
                if (myarges[0] == "Down")
                {
                    SendData(Rs232_str[1]);
                }
                if (myarges[0] == "On")
                {
                    SendData(Rs232_str[0]);
                }
                if (myarges[0] != "Down" && myarges[0] != "On")
                {
                    MessageBox.Show("参数错误");
                }
            }


                    
        }
        private void RS232_reset()
        {
            lokal_seting();
            setbut();
            setHeight();
            setrfttop();

        }
          

        //动态添加按钮，设置布局，text，name，鼠标悬浮标签
        private ArrayList Read_txt()
        {
            //读取本地txt文件返回string数组 //是文件中的注释行不会被读取
            ArrayList str = new ArrayList();
            //Encoding.Default制定默认编码可以读取中文

            if (!System.IO.File.Exists(inifilename))
            {
                //MessageBox.Show("配置错误，请联系13309512124");
                MessageBox.Show("请检查配置文件是否存在！");
                //退出程序
                Environment.Exit(0);
            }
            //打开文件
            StreamReader objReader = new StreamReader(inifilename, Encoding.Default);
            string sLine = "";
            while (sLine != null)
            {
                //逐行读取
                sLine = objReader.ReadLine();
                if (sLine != null && !sLine.Equals(""))
                {
                    //追加在str后面
                    str.Add(sLine);
                }
            }
            //关闭对象
            objReader.Close();
            return str;
        }

        private void lokal_seting()
        {
            //端口配置开关
            bool serialport=true;
            //计数器
            int i = 0;
            //从本地TXT读取信息到ArrayList readtxt
            ArrayList readtxt=Read_txt();
            //逐行读取string[]的内容，使用了泛型obj
            foreach (object obj in readtxt)
             {
                string ReadTxtline= (string)obj;
                //去除注释
                if(ReadTxtline[0]!='/')
                {
                    //配置文件使用#来判读是端口设置还是串口信号设置，所以#开头的只能有一行
                    if (ReadTxtline[0] == '#') 
                    {
                        serialport = false;
                        i=0;
                    }
                    if (serialport)
                    {
                        //端口配置
                        if (ReadTxtline != null)
                        {
                            //逐行存储配置，频率，位数，端口号，第一启动软件，以及延时时间，第二启动软件，延时时间
                            System_set[i] = ReadTxtline;
                            i = i + 1;
                        }
                    }
                    else
                    {
                        if (ReadTxtline[0] != '#')
                        {
                            //在读取的一行中使用%分割为数组
                            string[] rs = ReadTxtline.Split('%');
                            if (rs.Length == 1)
                            {
                                //如果只有串号
                                Rs232_str[i] = rs[0];
                                i = i + 1;
                            }
                            else
                            {
                                //本行配置是否生效

                                bool myv = bool.Parse(rs[0]);
                                //优化
                                if (myv)
                                {
                                    //visible_str[i] = myv;
                                    but_con = but_con + 1;
                                    Rs232_str[i] = rs[1];
                                    tooltip_str[i] = rs[2];
                                    i = i + 1;
                                }
                          


                                //原来
                                //if (rs[0] != null && myv)
                                //{
                                //    visible_str[i] = myv;
                                //    if (visible_str[i]) but_con = but_con + 1;
                                //}
                                //if (rs[1] != null && myv) Rs232_str[i] = rs[1];
                                //if (rs[2] != null && myv) tooltip_str[i] = rs[2];
                                //if (myv) i = i + 1;
                                //bool myv = bool.Parse(rs[0]);


                            }
                        }
                    }
                }
             }

        }

        private void setbut()
        {
            //根据读取的配置文件的到数组动态添加but，并绑定事件
            try
            {
                for (int i = 0; i < but_con; i++)
                {
                    Button bt = new Button();
                    //设定位置
                    bt.Height = 25;
                    bt.Width = 100;
                    bt.Left = 10 + (i % 3) * 102;
                    bt.Top = 40 + (i / 3) * 27;
                    bt.Name = "butgroup" + (i + 10);
                    bt.Text = tooltip_str[i];
                    bt.Tag = i;

                    //增加单击事件的监听                     
                    bt.MouseClick +=new MouseEventHandler(butgroup_click);
                    toolTip1.SetToolTip(bt, Rs232_str[i]);
                    //添加控件
                    this.Controls.Add(bt);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message); ;
            }
        }
        private void butgroup_click(object sender, EventArgs e)
        {
            //根据获取but的tag值发送不同的串号
            Button button = sender as Button;
            if (button == null) return;
            int i = (int)button.Tag;
            SendData(Rs232_str[i]);
        }
        private void setHeight()
        {
            //设置窗口高度
            this.Height =110 + (but_con / 3) * 27;
        }
        private void setrfttop()
        {
            //设置监视窗口位置
            rtfTerminal.Top = 80 + (but_con / 3) * 27;
        }

        //初始化端口
        private void InitSeriaPort()
        {
            //可能因为其他软件开启了串口，要关闭串口并在开始前配置合适的参数
            if (comport.IsOpen)
            {
                comport.Close();
                MessageBox.Show("可能因为其他软件开启了串口，已经由开启变为关闭状态，请重复干才的操作");
            }
            else
            {
                //根据本地系统设置，打开通信端口
                //设置比特率
                comport.BaudRate = Convert.ToInt32(System_set[0]);
                //设置每个字节的标准数据位长度
                comport.DataBits = Convert.ToInt32(System_set[1]);
                //设置每个字节的标准停止位数
                //comport.StopBits = Settings.Default.StopBits;
                //设置奇偶校验协议
                //comport.Parity = Settings.Default.Parity;
                //设置通信端口
                comport.PortName = System_set[2];


                //开启通信端口
                if (CheckCom(System_set[2])) comport.Open();
                else
                {
                    Log(LogMsgType.Outgoing, "端口设置错误，或者您的计算机就没有COM端口");

                }

                if (comport.IsOpen)
                {
                    //向日志发送信息
                    Log(LogMsgType.Outgoing, "通信端口开启");
                }
            }
        }

        //关闭端口
        private void CloseSeriaPort()
        {
            if (comport.IsOpen) comport.Close();
            Log(LogMsgType.Outgoing, "通信端口关闭");
        }

        //发送数据
        private void SendData(string sendstr)
        {
            //启动端口
            InitSeriaPort();
            byte[] data = HexStringToByteArray(sendstr);
            // 发送有十六进制得到序列转好成的二进制序列
            if (CheckCom(System_set[2]))
            {
                //发送二进制串号
                comport.Write(data, 0, data.Length);
                Log(LogMsgType.Outgoing, ByteArrayToHexString(data) + "发送完成");
            }
            else
            {
                Log(LogMsgType.Outgoing, "端口设置错误，或者您的计算机就没有COM端口");
            }
            //关闭端口
            CloseSeriaPort();
        }

        private bool CheckCom(string ComName)
        {
            bool HaveCOM;
            HaveCOM = false;
            foreach (string s in SerialPort.GetPortNames())
                if (s == ComName) HaveCOM = true;
            return HaveCOM;
        }

        private byte[] HexStringToByteArray(string s)
        {
            //十六进制转byte
            s = s.Replace(" ", "");
            //去除空格
            double str_up_length;
            double s_length;
            s_length = s.Length;
            //一个十六进制是4个bit，一个bype是8个bit所以数列长度缩短一半
            str_up_length = Math.Ceiling(s_length / 2);
            if ((2 * str_up_length - s_length) != 0)
            {
                //检测十六进制数，是否是偶数位
                Log(LogMsgType.Outgoing, "16进制需要是偶数位 控制码错误");
                byte[] buffer = new byte[s.Length / 2];
                return buffer;
            }
            else
            {

                byte[] buffer = new byte[s.Length / 2];
                //一次取两个十六进制数
                for (int i = 0; i < s.Length; i += 2)
                {
                    //把取到的两位string转化为二进制
                    buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16);
                }
                return buffer;
            }
        }

        private string ByteArrayToHexString(byte[] data)
        {
            StringBuilder sb = new StringBuilder(data.Length * 3);
            foreach (byte b in data)
                //如果byte是0000 0001 0000 0010转化为二进制应该是“01 02”，PadLeft(2, '0')如果不够两位前面填充0 ，PadRight(3, ' '）每两位一个空格
                sb.Append(Convert.ToString(b, 16).PadLeft(2, '0').PadRight(3, ' '));
            return sb.ToString().ToUpper();
        }

        private void Log(LogMsgType msgtype, string msg)
        {
            //我自己不太明白
            rtfTerminal.Invoke(new EventHandler(delegate
            {
                rtfTerminal.SelectedText = string.Empty;
                rtfTerminal.AppendText(msg + "\n");
                rtfTerminal.ScrollToCaret();
            }));
        }

        private void 监控ToolStripMenuItem_Click(object sender, EventArgs e)
        {
           //显示或者隐藏监视窗口
            if (OnWatch)
            {
                OnWatch =false;
                this.Height = this.Height - 160;
            }
            else
            {
                OnWatch = true;
                this.Height = this.Height + 160;
            }
        }
        //捕捉关机事件后，重载WndProc(ref Message m)增加自己的处理代码后，base.WndProc(ref m);
        //当用户选择结束对话框或程序自己调用ExitWindows函数 
        public const int WM_QUERYENDSESSION = 0x0011;   

        protected override void WndProc(ref Message m)
        {
     
            switch (m.Msg)
            {
                //此消息在OnFormClosing之前
                case WM_QUERYENDSESSION:
                    SendData(Rs232_str[1]);
                    //MessageBox.Show("发送关机串号后的验证信息");
                    break;
                default:
                    break;
            }
            base.WndProc(ref m);
        }

        private void 帮助ToolStripMenuItem_Click(object sender, EventArgs e)
        {
           // AutoDown autodown = new AutoDown();
           // autodown.Show();
            MessageBox.Show("感谢家人对我的关爱和网友的支持。\n本次改版是投影机控制工具的第三版：\n 1.配置文件一定要严格按照配置文件的样板写，程序没有对配置文件的有效性做验证，如果配置文件格式不对，程序会出错，或者不能控制投影机。\n 2.工具根据配置文件动态增加按钮，最多支持100个按钮。\n 3.本工具打开时自动发送投影机开机串号，如果把软件快捷方式放在启动菜单中，就可以实现电脑开机投影机自己开机。\n 4.本工具捕获WM_QUERYENDSESSION消息后发送投影机关机串号。\n 5.开机信号一定要放在第一行，关机信号一定要放在第二行。\n 6.程序支持 参数“Doen”和“On”发送开机关机串号。\n 7.开发者QQ 68817033 ");

        }
        //C#最小化到托盘+双击托盘恢复 
        //双击托盘托盘图标恢复正常窗体
        private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)

        {
            this.ShowInTaskbar = true;  //显示在系统任务栏  
            this.WindowState = FormWindowState.Normal;  //还原窗体
            this.notifyIcon1.Visible = false;  //托盘图标隐藏 
            //可以在这里增加授权
            //check mycheck = new check();
            //mycheck.ShowDialog();
            //if (mycheck.DialogResult==DialogResult.OK)
            //{
            //    this.ShowInTaskbar = true;  //显示在系统任务栏  
            //    this.WindowState = FormWindowState.Normal;  //还原窗体
            //    this.notifyIcon1.Visible = false;  //托盘图标隐藏  
            //}
            //else
            //{
            //    MessageBox.Show("授权码不正确，不能使用面板");
            //}
        }
        //窗体被单击最小化后，自身隐藏，进入系统托盘
        private void Form1_SizeChanged(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Minimized)
            {
                this.notifyIcon1.Visible = true;
                this.ShowInTaskbar = false;
            }
            else
            {
                notifyIcon1.Visible = false;
            }
        }
        //首次加载窗体，是它隐藏到系统托盘
        private void Form1_Shown(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Minimized;
            this.ShowInTaskbar = false;
            this.notifyIcon1.Visible = true;
            SendData(Rs232_str[0]);
            if (System_set[3] != null && System_set[4] != null)
            {
                RHstart(System_set[3], int.Parse(System_set[4]));
            }
            if (System_set[5] != null && System_set[6] != null)
            {
                RHstart(System_set[5], int.Parse(System_set[6]));

            }
        }
        private void StartPlay(string video_dir,int d_time)

        {
            Delay(d_time);
            //MyPlay myplay = new MyPlay(video_dir);
            //MyPlay myplay = MyPlay.CreateFrom(video_dir);
            //myplay.Show();
            //myplay.Activate();
        }

        private void 播放视频ToolStripMenuItem_Click(object sender, EventArgs e)
        {
           
           // StartPlay(System_set[5],0);
            RHstart(System_set[5], 0);
        }

        private void toolStripMenuItem1_Click(object sender, EventArgs e)
        {
            RHstart(System_set[3],0);
        }
        private void RHstart(string RH_dir,int d_time)
        {
            Delay(d_time);
            out_program(RH_dir);
        }
        //启动外部程序
        Process pro = new Process();
        private void out_program(string RHappname)

        {
            if (RHappname != null)
            {
                if (System.IO.File.Exists(RHappname))
                {
                    pro.StartInfo.FileName = RHappname;
                    pro.Start();
                }
                else
                {
                    MessageBox.Show("配置文件中指定启动的程序不存在，请检查配置文件");
                }
            }
        }
        //延时小函数
        public static bool Delay(int delayTime)
        {
            DateTime now = DateTime.Now;
            int s;
            do
            {
                TimeSpan spand = DateTime.Now - now;
                s = spand.Seconds;
                Application.DoEvents();
            }
            while (s < delayTime);
            return true;
        }


    }
}
